공공데이터포털 웹사이트에서 코로나19 감염 현황에 대한 API를 제공하고 있다. 전반적인 감염현황과 함께 연령별, 성별, 시도별 현황 정보도 함께 제공하고 있다.
먼저 감염현황에 대한 데이터를 가져온다. 공공데이터포털에서 발급된 API KEY는 usethis::use_r_environ() 명령어로 외부에 노출되지 않도록 .Renviron 환경변수에 저장하여 Sys.getenv('COVID_APIKEY') 명령어로 API로 호출시 활용한다.
library(tidyverse)
library(httr)
library(rvest)
library(glue)
readRenviron("~/.Renviron")
covid_confirmed_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20200410",
"&endCreateDt = 20200410") %>% str_remove_all(., " ")
covid_confirmed_resp <- GET(covid_confirmed_api) %>%
content(.)
covid_confirmed_resp %>%
listviewer::jsonedit()특정 날짜(“2020-04-10”)에 대해 확진자 현황 데이터를 얻게 되었다면 다음 단계로 JSON 자료형을 데이터프레임으로 변환시킨다. “공공데이터 오픈API 활용가이드” 에 나온 응답결과에 대한 명세서에 나온 주요 필드값은 다음과 같다.
ACC_EXAM_CNT : 누적 검사 수ACC_EXAM_COMP_CNT: 누적 검사 완료 수ACC_DEF_RATE : 누적 환진률DECIDE_CNT : 확진자 수RESUTL_NEG_CNT : 결과 음성 수EXAM_CNT : 검사진행 수DEATH_CNT : 사망자 수CARE_CNT : 치료중 환자 수CLEAR_CNT : 격리해제 수covid_confirmed_df <- tibble(
"날짜" = map_chr(covid_confirmed_resp$response$body$items, "createDt"),
"누적검사자" = map_chr(covid_confirmed_resp$response$body$items, "accExamCnt"),
"누적확진자" = map_chr(covid_confirmed_resp$response$body$items, "accExamCompCnt"),
"누적사망율" = map_chr(covid_confirmed_resp$response$body$items, "accDefRate"),
"검사자" = map_chr(covid_confirmed_resp$response$body$items, "examCnt"),
"확진자" = map_chr(covid_confirmed_resp$response$body$items, "decideCnt"),
"누적사망자" = map_chr(covid_confirmed_resp$response$body$items, "deathCnt"),
"치료중" = map_chr(covid_confirmed_resp$response$body$items, "careCnt"),
"누적격리해제" = map_chr(covid_confirmed_resp$response$body$items, "clearCnt"),
"누적음성판정" = map_chr(covid_confirmed_resp$response$body$items, "resutlNegCnt")
)
covid_confirmed_df기간을 확대하여 전체 기간으로 코로나바이러스감염증 감염현황 데이터를 추출한다.
covid_confirmed_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20200101",
"&endCreateDt = 20201226") %>% str_remove_all(., " ")
covid_confirmed_resp <- GET(covid_confirmed_api) %>%
content(.)
covid_confirmed_df <- tibble(
"날짜" = map_chr(covid_confirmed_resp$response$body$items$item, "createDt", .default = NA),
"누적검사자" = map_chr(covid_confirmed_resp$response$body$items$item, "accExamCnt", .default = NA),
"누적확진자" = map_chr(covid_confirmed_resp$response$body$items$item, "accExamCompCnt", .default = NA),
"누적사망율" = map_chr(covid_confirmed_resp$response$body$items$item, "accDefRate", .default = NA),
"검사자" = map_chr(covid_confirmed_resp$response$body$items$item, "examCnt", .default = NA),
"확진자" = map_chr(covid_confirmed_resp$response$body$items$item, "decideCnt", .default = NA),
"누적사망자" = map_chr(covid_confirmed_resp$response$body$items$item, "deathCnt", .default = NA),
"치료중" = map_chr(covid_confirmed_resp$response$body$items$item, "careCnt", .default = NA),
"누적격리해제" = map_chr(covid_confirmed_resp$response$body$items$item, "clearCnt", .default = NA),
"누적음성판정" = map_chr(covid_confirmed_resp$response$body$items$item, "resutlNegCnt", .default = NA)
)
covid_confirmed_df %>%
write_rds("data/covid_confirmed_api_orig.rds")
covid_confirmed_df %>%
arrange(날짜) %>%
reactable::reactable()먼저 특정일(2020-12-20) 기준 데이터를 추출해보자. 공공데이터 포털에 API를 요청하게 되면 결과값이 JSON으로 반환되어 먼저 자료형을 일별한다.
covid_gender_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19GenAgeCaseInfJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20201220",
"&endCreateDt = 20201220") %>% str_remove_all(., " ")
covid_resp <- GET(covid_gender_api) %>%
content(.)
covid_resp %>%
listviewer::jsonedit()JSON을 데이터프레임으로 변환시킨다. 성별과 연령대가 뒤섞여 있기 때문에 성별과 연령 데이터프레임으로 나눈다.
covid_dat <- tibble(
"날짜" = map_chr(covid_resp$response$body$items$item, "createDt"),
"확진자" = map_int(covid_resp$response$body$items$item, "confCase"),
"감염율" = map_chr(covid_resp$response$body$items$item, "confCaseRate"),
"사망자" = map_int(covid_resp$response$body$items$item, "death"),
"치명율" = map_chr(covid_resp$response$body$items$item, "deathRate"),
"구분" = map_chr(covid_resp$response$body$items$item, "gubun")
)
covid_dat# A tibble: 11 x 6
날짜 확진자 감염율 사망자 치명율 구분
<chr> <int> <chr> <int> <chr> <chr>
1 2020-12-20 14:14:21.025 1638 3.300000 0 0.00 0-9
2 2020-12-20 14:14:21.024 3105 6.250000 0 0.00 10-19
3 2020-12-20 14:14:21.024 8455 17.020000 0 0.00 20-29
4 2020-12-20 14:14:21.024 6297 12.680000 2 0.30 30-39
5 2020-12-20 14:14:21.024 6975 14.040000 6 0.890000 40-49
6 2020-12-20 14:14:21.024 9207 18.540000 28 4.150000 50-59
7 2020-12-20 14:14:21.024 7722 15.550000 81 12.020000 60-69
8 2020-12-20 14:14:21.024 3892 7.840000 200 29.670000 70-79
9 2020-12-20 14:14:21.023 2374 4.780000 357 52.970000 80 이상
10 2020-12-20 14:14:21.023 25797 51.940000 329 48.810000 여성
11 2020-12-20 14:14:21.023 23868 48.060000 345 51.190000 남성
하루를 넘어 전체 기간에 대해서 연령별, 성별 코로나19 데이터를 가져온다. 2020-04-01 부터 데이터를 제공하기 때문에 시작일을 2020-04-01 으로 특정하여 현재까지 데이터를 가져온다.
library(lubridate)
# 전체 데이터 -----
covid_age_gender_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19GenAgeCaseInfJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20200401",
"&endCreateDt = 20201225") %>% str_remove_all(., " ")
covid_age_gender_resp <- GET(covid_age_gender_api) %>%
content(.)
covid_age_gender_df <- tibble(
"날짜" = map_chr(covid_age_gender_resp$response$body$items$item, "createDt"),
"확진자" = map_int(covid_age_gender_resp$response$body$items$item, "confCase"),
"감염율" = map_chr(covid_age_gender_resp$response$body$items$item, "confCaseRate"),
"사망자" = map_int(covid_age_gender_resp$response$body$items$item, "death"),
"치명율" = map_chr(covid_age_gender_resp$response$body$items$item, "deathRate"),
"구분" = map_chr(covid_age_gender_resp$response$body$items$item, "gubun")
)
covid_age_gender_df %>%
write_rds("data/covid_age_gender.rds")
covid_age_gender_df# A tibble: 2,861 x 6
날짜 확진자 감염율 사망자 치명율 구분
<chr> <int> <chr> <int> <chr> <chr>
1 2020-12-25 14:12:01.023 1844 3.370000 0 0.00 0-9
2 2020-12-25 14:12:01.023 3403 6.210000 0 0.00 10-19
3 2020-12-25 14:12:01.023 9042 16.510000 0 0.00 20-29
4 2020-12-25 14:12:01.023 6948 12.690000 3 0.390000 30-39
5 2020-12-25 14:12:01.023 7695 14.050000 7 0.910000 40-49
6 2020-12-25 14:12:01.023 10248 18.710000 30 3.880000 50-59
7 2020-12-25 14:12:01.022 8589 15.680000 90 11.640000 60-69
8 2020-12-25 14:12:01.022 4321 7.890000 227 29.370000 70-79
9 2020-12-25 14:12:01.022 2680 4.890000 416 53.820000 80 이상
10 2020-12-25 14:12:01.022 28235 51.550000 383 49.550000 여성
# ... with 2,851 more rows
시도별로 코로나19 확진자 및 사망자 데이터를 추출한다. 공공데이터 포털에 API를 요청하게 되면 결과값이 JSON으로 반환되어 먼저 자료형을 일별한다.
covid_sido_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19SidoInfStateJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20200410",
"&endCreateDt = 20200410") %>% str_remove_all(., " ")
covid_sido_resp <- GET(covid_sido_api) %>%
content(.)
covid_sido_resp %>%
listviewer::jsonedit()JSON을 데이터프레임으로 변환시킨다. 이를 위해서 중요한 필드를 정의하면 다음과 같다.
CREATE_DT : 등록일시분초DEATH_CNT : 사망자 수GUBUN : 시도명(한글)INC_DEC : 전일대비 증감 수ISOL_CLEAR_CNT: 격리 해제 수QUR_RATE : 10만명당 발생률DEF_CNT : 확진자 수ISOL_ING_CNT : 격리중 환자수OVER_FLOW_CNT : 해외유입 수LOCAL_OCC_CNT : 지역발생 수covid_sido_dat <- tibble(
"날짜" = map_chr(covid_sido_resp$response$body$items$item, "createDt"),
"시도" = map_chr(covid_sido_resp$response$body$items$item, "gubun"),
"확진자" = map_chr(covid_sido_resp$response$body$items$item, "defCnt"),
"해외유입" = map_chr(covid_sido_resp$response$body$items$item, "overFlowCnt"),
"지역발생" = map_chr(covid_sido_resp$response$body$items$item, "localOccCnt"),
"10만_발생률" = map_chr(covid_sido_resp$response$body$items$item, "qurRate"),
"누적사망자" = map_chr(covid_sido_resp$response$body$items$item, "deathCnt"),
"사망자" = map_chr(covid_sido_resp$response$body$items$item, "incDec"),
"격리해제" = map_chr(covid_sido_resp$response$body$items$item, "isolClearCnt")
)
covid_sido_dat하루를 넘어 전체 기간에 대해서 시도별 코로나19 데이터를 가져온다. 전체기간을 대상으로 데이터를 가져온다.
# 전체 데이터 -----
covid_sido_api <- glue("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19SidoInfStateJson",
"?serviceKey = {Sys.getenv('COVID_APIKEY')}",
"&pageNo = 1",
"&numOfRows = 10",
"&startCreateDt = 20200101",
"&endCreateDt = 20201226") %>% str_remove_all(., " ")
covid_sido_resp <- GET(covid_sido_api) %>%
content(.)
covid_sido_df <- tibble(
"날짜" = map_chr(covid_sido_resp$response$body$items$item, "createDt", .default = NA),
"시도" = map_chr(covid_sido_resp$response$body$items$item, "gubun", .default = NA),
"확진자" = map_chr(covid_sido_resp$response$body$items$item, "defCnt", .default = NA),
"해외유입" = map_chr(covid_sido_resp$response$body$items$item, "overFlowCnt", .default = NA),
"지역발생" = map_chr(covid_sido_resp$response$body$items$item, "localOccCnt", .default = NA),
"10만_발생률" = map_chr(covid_sido_resp$response$body$items$item, "qurRate", .default = NA),
"누적사망자" = map_chr(covid_sido_resp$response$body$items$item, "deathCnt", .default = NA),
"사망자" = map_chr(covid_sido_resp$response$body$items$item, "incDec", .default = NA),
"격리해제" = map_chr(covid_sido_resp$response$body$items$item, "isolClearCnt", .default = NA)
)
covid_sido_df %>%
write_rds("data/covid_sido_orig.rds")
covid_sido_df %>%
arrange(날짜) %>%
reactable::reactable()데이터 과학자 이광춘 저작
kwangchun.lee.7@gmail.com